
"""---------------------------------------------------------------------------------------------
  
   INTRODUCTION TO NGMATH
  
        The ngmath library is a collection of interpolators and approximators for one-dimensional, two-dimensional
        and three-dimensional data. The packages, which were obtained from NCAR, are:
 
            natgrid -- a two-dimensional random data interpolation package based on Dave Watson's nngridr.
 
            dsgrid --  a three-dimensional random data interpolator based on a simple inverse distance weighting
                       algorithm.
 
            fitgrid -- an interpolation package for one-dimensional and two-dimensional gridded data based on 
                       Alan Cline's Fitpack. Fitpack uses splines under tension to interpolate in one and two
                       dimensions.
 
            csagrid -- an approximation package for one-dimensional, two-dimensional and three-dimensional random 
                       data based on David Fulker's Splpack. csagrid uses cubic splines to calculate its
                       approximation function.
 
            cssgrid -- an interpolation package for random data on the surface of a sphere based on the work of
                       Robert Renka. cssgrid uses cubic splines to calculate its interpolation function.
 
            shgrid --  an interpolation package for random data in 3-space based on the work of Robert Renka. 
                       shgrid uses a modified Shepard's algorithm to calculate its interpolation function.
  
   COMPARISION OF NGMATH PACKAGES
  
        Three-dimensional packages -- shgrid, csagrid and dsgrid.
 
            shgrid is probably the package of choice for interpolation. It uses a least squares fit of biquadratics
            to construct its interpolation function. The interpolation function will pass through the original data 
            points. 
 
            csagrid uses a least squares fit of cubic splines to calculate its approximation function: the calculated
            surface will not necesarily pass through the original data points. The algorithm can become unstable in data
            sparse regions.
 
            dsgrid uses a weighted average algorithm and is stable in all cases, but the resultant interpolation is
            not usually smooth and execution time is very slow. dsgrid is probably best used when csagrid and shgrid
            fail or for comparative purposes.
  
        Two-dimensional packages -- natgrid, fitgrid, csagrid and dsgrid.
 
            natgrid is the package of choice in most cases. It implements a very stable algorithm and has parameters
            for adjusting the smoothness of the output surface. 
 
            fitgrid offers user-settable parameters for specifiying derivatives along the boundary of the output grid
            which are not available in natgrid.
 
            csagrid produces an approximate two-dimensional surface which may be smoother than that produced by fitgrid
            and natgrid.
 
            dsgrid is not recommended for two-dimensional surfaces. natgrid is superior in all respects.
  
        One-dimensional packages -- fitgrid  and csagrid.
 
            fitgrid is definitely the package of choice. It has many features not available in csagrid, such as
            interpolating parametric curves, finding integrals, handling periodic functions, allowing smoothing that
            varies from linear to a full cubic spline interpolation and specifying slopes at the end points.
  
        Interpolation on a sphere -- cssgrid.
 
            cssgrid is designed specifically for interpolating on a sphere. It uses cubic splines to calculate an
            interpolation function.
  
   SHGRID PACKAGE
  
        shgrid interpolates random data in 3-space. and it provides the means for finding the nearest point or points to
        a given point in 3-space. shgrid constructs a once-continuously differentiable function that interpolates the
        original data. This function is constructed as follows. First, for each input point a bivariate quadratic is
        computed that interpolates the functional value at the data point in a least squares fit to neighboring data
        values. How close the bivariate quadratic comes to the functional values is attenuated by an inverse distance
        weighting. That is, the calculated bivariate quadratic will fit the functional values at nearby points better
        than at farther points. After the bivariate quadratics are calculated, the interpolating function is calculated
        as a weighted average of the bivariate quadratics. 
 
   SHGRID CONTENTS
  
        Access through Python to the shgrid package from NCAR's ngmath distribution is provided directly through the module
        shgridmodule.so which was generated by connecting the Fortran routines to Python using the Pyfort implementation
        by Paul Dubois.
        
                    Single precision procedures:                                                    
                                                                                                
                        shgrid  -- interpolates 3D random data
 
                        shgetnp -- finds nearest points to a given point in 3-space
 
                        shseti  -- sets values for the integer control parameters
 
                        shgeti  -- retrieves values for the integer control parameters
 
   REQUIRED FILE
 
        shgridmodule.so -- the Python interface to the ngmath shgrid package.
 
   USEFUL FILES
 
        sh.py         -- the object oriented interface including a general help package.
        shgridtest.py -- the code to test sh.py and to write documentation.

   USAGE
 
        This module is designed to use in two ways. One is through the use of the object oriented interface to the underlying
        functions. This approach is recommended for users not already familiar with the original shgrid distribution because
        it simplifies the calls to the routines. The other method uses the original functions calling them directly from Python. 
 
                    --------------------------------------------------------------
                    -------------------  OBJECT ORIENTED APPROACH ----------------
 
            The sh module contains the Shgrid class and the single method rgrd. Use of this object oriented scheme is a two
            step process. The first is making an instance of the class which envolves submitting the appropriate grid for the
            task at hand. There are two choices: make an interpolation to a three dimensional grid or find the nearest points
            to a specific point which has been already set in making the instance.
 
            STEP 1. 

            Array Input And Output Case In Preparation For Interpolation In 3-space

                To make an instance, r, type:
 
                    import sh

                    r = sh.Shgrid(xi, yi, zi, xo, yo, zo) 

                       where xi, yi and zi are the input coordinate arrays in list format
                       while xo, yo and zo are the output grid coordinate arrays which
                       must be increasing but need not be evenly spaced.
        
            Array Input And Single Point Output Case In Preparation For Finding Nearest Points In 3-space

                To make an instance, r, type:
 
                    import sh

                    r = sh.Shgrid(xi, yi, zi, px, py, pz) 

                       where xi, yi and zi are the input coordinate arrays in list format
                       while px, py and pz are the coordinates of a point whose nearest
                       neighbors are to be found. 

     
            To look at the default settings for the control parameters and a brief description or thier
            properties, type

                r.printDefaultParameterTable()
 
            To change a setting type the new value. For example, to set ncl to 8, type
 
                r.ncl = 1
 
            To find an individual value,  type the name. For example, to exam the value of nfl, type
 
                r.nfl
     
            To check the settings type
     
                r.printInstanceParameterTable() -- prints the table with values and a description of the parameters
                                                   used in subsequent calls to the method function rgrd
                or

                r.printInstanceParameters()     -- prints a list of the parameters values used in subsequent calls to the 
                                                   the rgrd method

                sh. printStoredParameters()    -- prints the parameters in memory which may differ from the above if the
                                                   user has made more than one instance of the Shgrid class.

            In the absence of an instance of the class Shgrid, a description of the control parameters can be found 
            by typing
     
               import sh
               sh.printParameterTable()
     
     
            STEP 2. 

            Interpolation In 3-space

                Type

                    dataOut = r.rgrd(dataIn) 

                        where dataIn is input data in list form  and dataOut is output data in gridded form

            Finding Nearest Points In 3-space

                Type

                    np = r.rgrd(numberPoints) 

                        where:
                            np is an array with the indices into the input data arrays of the sequence of nearest points
                            numberPoints is the number of nearest points requested. It may be 1.

               For the ith element in np the point in 3-space is ( xi[np[i]], yi[np[i]], zi[np[i]] ).

                    --------------------------------------------------------------
                    -------------------  ORIGINAL FUNCTION APPROACH -----------------

            The module shgridmodule.so exports the following functions to Python from the original Fortran library:
        
                    Single precision procedures:                                                    
                                                                                                
                        shgrid  -- interpolates 3D random data
 
                        shgetnp -- finds nearest points to a given point in 3-space
 
                        shseti  -- sets values for the integer control parameters
 
                        shgeti  -- retrieves values for the integer control parameters
 
                                                                                                
            Information on the use of the routines is available by importing shgridmodule and printing the docstring
            of interest. For example, documentation for the routine shgrid is obtained by typing
 
                import shgridmodule

                print shgridmodule.shgrid.__doc__
 
            The documentation associated with the shgridmodule.so, such as the doctrings, describe the Fortran code. The
            indices start with 1 (not 0 as in the Python interface) and the arrays are transposes as nomenclature. For
            example, the Fortran array dimensioned as (x,y,z) is the same physically as the Python or C array dimensioned as 
            (z,y,x). Since the calls are from Python the array indices start with 0. It is only in a request for a specific 
            index submitted to Fortran that the indices start at 1. 

            The long and the short of this is as follows. If you use the interface, indices start at 0. If you call the routines
            directly, in specific requests indices start at 1. In either case, data is passed with the x index moving
            fastest. 
 
            This same information is available in the help package.
 
                import sh

                print sh.help('shgrid')
 
            A description of the control parameters is not in the shgridmodule documentation. It can be found by typing
 
                import sh
                sh.printParameterTable()
 
   DOCUMENTATION
  
        Documentation is provided through Python's docstrings, essentially Python style program comments. A help package
        provides instructions on the use of shgrid. A table of contents is printed to the screen by typing
  
                sh.help()
  
        after importing sh.
  
        A hard copy of this documentation is written to the file shgridmodule.doc after import shgridtest by typing 
  
               shgridtest.document() 
  
   TESTING 
 
       To run a some tests of the 3D interpolation and the nearest point computattion and to get a copy of this documentation,
       type
                       
           cdat shgridtest.py
 
--------------------------------------------------------------------------------------------------------------"""
import math, string, sys, numpy, shgridmodule

#shgridmodule.set_pyfort_option(shgridmodule.MIRROR)

writeTestcase = 'yes'
try:
    import cdms
except ImportError:
    print 'Can not write test case results to netCDF files without module cdms'
    writeTestcase = 'no'

usefilled = 'yes'
try:
    import MA
except ImportError:
    print 'Can not convert from MA array to numpy array without module MA'
    usefilled = 'no'

debug = 0

class Shgrid:

    #---------------------------------------------------------------------------------
    # 
    #       Contents of Csagrid class
    #                
    #---------------------------------------------------------------------------------

    def __init__(self, xi, yi, zi, xo, yo, zo): 

        """    --------------------------------------------------------------------------------------------------------
             ROUTINE:  __init__
         
             PURPOSE:  init makes an instance, r,  of the Shgrid class while performing the following:
         
                           checks the argument list for the correct types.
         
                           establishes the default parameter instance data
         
                           assigns the coordinate grid arrays to self data
         
                           sets the subsequent function choice in rgrd to shgrid or shgetnp
         
             USAGE:    r = fit.Csagrid(xi, yi, zi, xo, yo, zo) where
         
                                xi, yi and zi are the input grid in list form. (each has the same length as the input data)
         
                                xo, yo and zo are either arrays specifying the outout grid if the request is for an interpolation
                                or a single point in 3-space if the request is for the nearest neighbors.        
                         
             definition: __init__(self, xi, yi, zi, xo, yo, zo) 
         
    --------------------------------------------------------------------------------------------------------""" 

        # -----  Evaluate the input grid  -----

        try:
            nxi = len(xi)
        except:                        
            msg = 'CANNOT CREATE INSTANCE - The first input dimension argument must be an array'
            raise TypeError, msg                        

        if xi.dtype.char != 'f':
            print 'Warning -- changing first input coordinate grid array to single precision'
            xi = xi.astype(numpy.float32)

        if nxi < 10:
            msg = 'CANNOT CREATE INSTANCE - The length of the first input dimension argument must be greater than 9'
            raise ValueError, msg                        

        try:
            nyi = len(yi)
        except:                        
            msg = 'CANNOT CREATE INSTANCE - The second input dimension argument must be an array'
            raise TypeError, msg                        

        if yi.dtype.char != 'f':
            print 'Warning -- changing second input coordinate grid array to single precision'
            yi = yi.astype(numpy.float32)

        if nyi < 10:
            msg = 'CANNOT CREATE INSTANCE - The length of the second input dimension argument must be greater than 9'
            raise ValueError, msg                        

        try:
            nzi = len(zi)
        except:                        
            msg = 'CANNOT CREATE INSTANCE - The third input dimension argument must be an array'
            raise TypeError, msg                        

        if zi.dtype.char != 'f':
            print 'Warning -- changing third input coordinate grid array to single precision'
            zi = zi.astype(numpy.float32)

        if nzi < 10:
            msg = 'CANNOT CREATE INSTANCE - The length of the third input dimension argument must be greater than 9'
            raise ValueError, msg                        


        if nxi != nyi and nxi != nzi:
            msg = 'CANNOT CREATE INSTANCE - Lengths of the arrays must be equal for listed input grid'
            raise ValueError, msg
        else:
            self.ni = nxi

        self.xi = xi
        self.yi = yi
        self.zi = zi

        # -----  Evaluate the output grid  -----

        pointCounter = 0
        gridCounter = 0
        try:
            self.nxo = len(xo)
            gridCounter = gridCounter + 1
        except TypeError:                        
            pointCounter= pointCounter + 1
            self.nxo = 1
        try:
            self.nyo = len(yo)
            gridCounter = gridCounter + 1
        except TypeError:                        
            pointCounter= pointCounter + 1
            self.nyo = 1
        try:
            self.nzo = len(zo)
            gridCounter = gridCounter + 1
        except TypeError:                        
            pointCounter= pointCounter + 1
            self.nzo = 1

        # -----  Choose interpolation or nearest neighbor determination-----

        if gridCounter == 3:
            self.callGridded = 'yes'
        elif pointCounter == 3:
            self.callGridded = 'no'
        else:
            msg = 'CANNOT CREATE INSTANCE - the output grid request must be 3 arrays or 3 values'
            raise ValueError, msg

        # ---- monotonicity and direction check of the grid ----
        if self.callGridded == 'yes':
            self.xo, self.yo, self.zo, monotonic, self.xreverse, self.yreverse, self.zreverse = checkdim(xo, yo, zo)
            if monotonic == 'no':
                msg = 'CANNOT CREATE INSTANCE - the output grid must be monotonic'
                raise ValueError, msg
        else:
            self.xo = xo
            self.yo = yo
            self.zo = zo
            self.xreverse = 'no'
            self.yreverse = 'no'
            self.zreverse = 'no'

        # ----- establish the parameter instance data using the default values -----

        defaultDict = Shgrid.makeDefaultParameterTable(self)

        n = self.ni
        self.ncl   = eval(defaultDict['ncl'][2])
        self.nfl   = eval(defaultDict['nfl'][2])
        self.nls   = eval(defaultDict['nls'][2])

    def rgrd(self, dataIn = None):

        """    --------------------------------------------------------------------------------------------------------
         
             ROUTINE: rgrd 
         
             PURPOSE:  To perform one of the following two possible computations in 3-space: 
                           To interpolate random data in 3-space using a modified Shepard's algorithm 
                           To find the nearest neighbor to a user specified point 
         
             USAGE:    To interpolate use
         
                           dataOut = r.rgrd(dataIn) where
                               
                               r       -- an instance of Shgrid
                               dataIn  -- input data 
                               dataOut -- output data 
         
                       To locate the nearest point use
         
                           np = r.rgrd(numberPoints) where
                               
                               r       -- an instance of Shgrid
                               np      -- the array with numberPoints indices into the input grid idenifying the nearest points
    --------------------------------------------------------------------------------------------------------""" 

        if self.callGridded == 'yes':                           # Interpolation in 3-space
            if usefilled == 'yes':
                dataIn = MA.filled(dataIn)

            if debug == 1:
                print 'calling shgrid' 

            iwk = numpy.zeros((2*self.ni,),'i')
            rwk = numpy.zeros((11*self.ni+6,),'f')
            dataOut, ier = shgridmodule.shgrid(self.xi, self.yi, self.zi,
                                               dataIn,
                                               self.xo, self.yo, self.zo,
                                               iwk,rwk)
            dataOut = numpy.transpose(dataOut)

            if debug == 1:
                print '*****************   returning from shgrid with  ier = ', ier

            if ier != 0:
                msg = 'Error in return from shgrid call with -- ' + Shgrid.errorTable(self)[ier]
                raise ValueError, msg

            # is a reverse the order in the returned arrays necessary?

            if (self.xreverse == 'yes') or (self.yreverse == 'yes') or (self.zreverse == 'yes'):
                needReverse = 'yes'
            else:
                needReverse = 'no'
            if needReverse == 'yes':
                dataOut = Shgrid.reverseData(self, dataOut)

            return dataOut 

    #---------------------------------------------------------------------------------

        else:                                                       # Computation of nearest neighbors
            if debug == 1:
                print 'calling shgetnp' 

            numberPoints = dataIn
            np = numpy.zeros((numberPoints,),numpy.int32)

            n = self.ni
            iwk = numpy.zeros((2*n,),numpy.int32)
            rwk = numpy.zeros((11*n + 6,), numpy.float32)

            iflag = 0
            np[0], ier = shgridmodule.shgetnp(self.xo, self.yo, self.zo,
                                              self.xi, self.yi, self.zi,
                                              iflag,
                                              iwk, rwk)

            if debug == 1:
                print '*****************   returning from shgrid with  ier = ', ier
            if ier != 0:
                msg = 'Error in return from shgetnp call with -- ' + Shgrid.errorTable(self)[ier]
                raise ValueError, msg

            iflag = 1
            for i in range(1, numberPoints):
                np[i], ier = shgridmodule.shgetnp(self.xo, self.yo, self.zo,
                                                  self.xi, self.yi, self.zi,
                                                  iflag,
                                                  iwk, rwk)

                if debug == 1:
                    print '*****************   returning from shgrid with  ier = ', ier
                if ier != 0:
                    msg = 'Error in return from shgetnp call with -- ' + Shgrid.errorTable(self)[ier]
                    raise ValueError, msg
            return np


    #---------------------------------------------------------------------------------
    # ****************  Control parameter manipulation functions  ********************
    #---------------------------------------------------------------------------------

    def parameterNames(self):
        #------------------------------------------------------------------------------
        #                                      
        #     purpose:  produce a list of the dsgrid parameters
        #
        #     usage:    parameters = parameterNames(self)
        #
        #     passed:   self
        #
        #     returned: parameters
        #
        #------------------------------------------------------------------------------

        parameters = ['name', '----', 'ncl', 'nfl', 'nls']

        return parameters 

    def makeDefaultParameterTable(self):
        #-----------------------------------------------------------------------------------
        #                                      
        #     purpose: construct the dictionary which is the default control parameters table
        #
        #     usage:   makeDefaultParameterTable(self)
        #
        #     passed:   self
        #
        #     returned: parameterDict
        #
        #----------------------------------------------------------------------------------

        parameterDict = {
      'name':('type ','     legal values      ','    default              ', '                     description                      '),
      '----':('-----','------------------- ---','------------------------ ', '------------------------------------------------------'),
      'ncl'  :(' int ','>ncl > 0              ','int(math.pow(n/3.,1./3.))', 'granularity of 3-D cell grid                          '),
      'nfl'  :(' int ','1<= nfl <= min(32,n-1)','min(32, n-1)             ', 'number of input data values within radius of influence'),
      'nls'  :(' int ','9<= nls <= min(17,n-1)','min(17, n-1)             ', 'number of data values used in the least square fit    ')}

        return parameterDict      

    def makeInstanceParameterTable(self):
        #----------------------------------------------------------------------------------
        #                                      
        #     purpose:  construct the dictionary which is the instance parameters table
        #
        #     usage:    makeInstanceParameterTable(self)
        #
        #     passed:   self
        #
        #     returned: parameterDict
        #
        #----------------------------------------------------------------------------------

        parameterDict = {
      'name': ('type ','     legal values     ','    value     ', '                     description                      '),
      '----': ('-----','----------------------','------------- ', '------------------------------------------------------'),
      'ncl' : (' int ','>ncl > 0              ',eval('self.ncl'), 'granularity of 3-D cell grid                          '),
      'nfl' : (' int ','1<= nfl <= min(32,n-1)',eval('self.nfl'), 'number of input data values within radius of influence'),
      'nls' : (' int ','9<= nls <= min(17,n-1)',eval('self.nls'), 'number of data values used in the least square fit    ')}

        return parameterDict      

    def printDefaultParameterTable(self):
        """    --------------------------------------------------------------------------------------------------------
                                               
              purpose: print the value of all the parameters
         
              usage:    r.printDefaultParameterTable()
         
                        where r is an instance of Dsgrid
         
              passed:   self
         
              returned: None
         
    --------------------------------------------------------------------------------------------------------""" 
        names = Shgrid.parameterNames(self)

        parameterDict = Shgrid.makeDefaultParameterTable(self)
        for item in names:
            items = (item, parameterDict[item][0], parameterDict[item][1], parameterDict[item][2], parameterDict[item][3])  
            print '%-6.6s  %-6.6s  %-22.22s   %-24.24s  %s' % items

        return 

    def printInstanceParameterTable(self):
        """    --------------------------------------------------------------------------------------------------------
                                               
              purpose: print the value of all the parameters
         
              usage:  r.printInstanceParameterTable()
         
                      where r is an instance of Dsgrid
         
              passed:   self
         
              returned: None
         
    --------------------------------------------------------------------------------------------------------""" 

        names = Shgrid.parameterNames(self)

        parameterDict = Shgrid.makeInstanceParameterTable(self)
        for item in names:
            items = (item, parameterDict[item][0], parameterDict[item][1], parameterDict[item][2], parameterDict[item][3])  
            print '%-6.6s  %-6.6s  %-22.22s   %-14.14s  %s' % items

        return 

    def printInstanceParameters(self):
        """    --------------------------------------------------------------------------------------------------------
                                               
              purpose: print the values of the current dsgrid control parameters in c code
         
              usage:    r. printInstanceParameters()
         
                      where r is an instance of Dsgrid
         
              passed:   self
         
              returned: None
         
    --------------------------------------------------------------------------------------------------------""" 

        names = Shgrid.parameterNames(self)
        names = names[2:]

        for name in names:
            print 'Currently,  %s = %d' % (name, eval('self.' + name))

        return None      


    def setInstanceParameters(self):
        #---------------------------------------------------------------------------
        #                                      
        #     purpose: set the instance values of the current shgrid control parameters in c code
        #
        #     usage:  r.setInstanceParameters() 
        #
        #             where r is an instance of Shgrid
        #
        #     passed:   self
        #
        #     returned: None
        #
        #----------------------------------------------------------------------------

        names = Shgrid.parameterNames(self)
        names = names[2:]

        for name in names:
            shgridmodule.shseti(name, eval('self.' + name))

        return None      

    #---------------------------------------------------------------------------------
    # *****************************  Error Table  ************************************
    #---------------------------------------------------------------------------------
    def errorTable(self):

        """    --------------------------------------------------------------------------------------------------------
                                             
            purpose: construct the dictionary which provides access to error messages
         
            usage:  errorDict = r.errorTable()
         
                    where r is an instance of Dsgrid
         
            returned: errorDict
         
    --------------------------------------------------------------------------------------------------------""" 

        errorDict = {
            0: 'No error',
            1: 'Number of input data points must be > 9.',
            2: 'Number of points used to calculate weights must be > 9.',
            3: 'Number of data points used in the least squares fit must be > 9.',
            4: 'Number of points used to calculate weights must be at least 1.',
            5: 'Number of data points used in the least squares fit too large. Should be greater than n but less than 41.',
            6: 'Number of points used to calculate weights too large. Should be greater than n but less than 41.',
            7: 'Cell grid dimensions must be positive.',
            8: 'Duplicate input points encountered.',
            9: 'Collinear input, no unique solution.',
           10: 'At least two points must have different x coordinates.',
           11: 'At least two points must have different y coordinates.',
           12: 'At least two points must have different z coordinates.',
           13: 'No cells contain a point within the radius of influence of the input point.',
           14: 'Negative search radius in calculating least squares fit.' }

        return errorDict      

    #---------------------------------------------------------------------------------
    # ***************************  magic functions   *********************************
    #---------------------------------------------------------------------------------

    def __setattr__(self, name, value):
        #---------------------------------------------------------------------------------
        #
        #   purpose:  '__setattr__' is called on every assignment to an instance attribute.
        #             Consequently, it must put the value in through the __dict__ to avoid
        #             calling itself and setting up an infinite recursion loop.It sets the
        #             attribute called name to value in two steps.
        #                 One -- set the global C code control parameter  
        #                 Two -- set the instance self data control parameter  
        #
        #   usage:    x.name = value   
        #
        #   passed :  name and value
        #
        #   returned: None
        #
        #---------------------------------------------------------------------------------
        names = Shgrid.parameterNames(self)
        names = names[2:]

        if name in names:
            shgridmodule.shseti(name, value)
            self.__dict__[name] = value

        else:
            self.__dict__[name] = value

        return None

    def __getattr__(self, name):
        #---------------------------------------------------------------------------------
        #
        #   purpose:  '__getattr__' is called only if a referenced attribute can not be found
        #             in the instance. It gets the attribute from shgridmodule if possible.
        #
        #   usage:    x.name  -- name is the oject and not a string repr   
        #
        #   passed :  name 
        #
        #   returned: x.name 
        #
        #---------------------------------------------------------------------------------

        names = Shgrid.parameterNames(self)
        names = names[2:]

        if name in names:
            value = shgridmodule.shgeti(name)

        else:
            value = self.__dict__[name]

        return value

    #---------------------------------------------------------------------------------
    # *******************************************************************
    # ****************  end of magic functions **************************
    # *******************************************************************
    #---------------------------------------------------------------------------------

    def reverseData(self, data):
        #------------------------------------------------------------------------------
        #                                      
        #     purpose: reverse the order of the data if outgrid submitted was not increasing
        #
        #     usage: data = r.reverseData 
        #
        #     returned: parameters
        #
        #------------------------------------------------------------------------------

        if self.zreverse == 'yes':
            data = data[::-1,:,:]
        if self.yreverse == 'yes':
            data = data[:,::-1,:]
        if self.xreverse == 'yes':
            data = data[:,:,::-1]

        return data 


def checkdim(x, y, z):
    #------------------------------------------------------------------------------------------
    #                                      
    #     purpose: determine whether the coordinate grid is random or monotonically increasing
    #
    #     usage:  
    #
    #     returned: x, y, z, monotonic, xreverse, yreverse, zreverse
    #
    #-------------------------------------------------------------------------------------------
    # x coordinate examination

    xsize = len(x)

    if x[0] > x[xsize - 1]:
        x = x[::-1]
        xreverse = 'yes'
    else:
        xreverse = 'no'


    xmonotonic = 'yes'                                  # monotonic and possibly reversed to make it montonically increasing
    for n in range(1, xsize):
        if x[n] < x[n - 1]:
            xmonotonic = 'no'                           # not monotonic so return the original grid

    # y coordinate examination

    ysize = len(y)

    if y[0] > y[ysize - 1]:
        y = y[::-1]
        yreverse = 'yes'
    else:
        yreverse = 'no'


    ymonotonic = 'yes'                                  # monotonic and possibly reversed to make it montonically increasing
    for n in range(1, ysize):
        if y[n] < y[n - 1]:
            ymonotonic = 'no'                           # not monotonic so return the original grid

    # z coordinate examination

    zsize = len(z)

    if z[0] > z[zsize - 1]:
        z = z[::-1]
        zreverse = 'yes'
    else:
        zreverse = 'no'


    zmonotonic = 'yes'                                  # monotonic and possiblz reversed to make it montonicallz increasing
    for n in range(1, zsize):
        if z[n] < z[n - 1]:
            zmonotonic = 'no'                           # not monotonic so return the original grid

    if xmonotonic == 'yes' and ymonotonic == 'yes' and zmonotonic == 'yes':   # if all monotonic, grid is monotonic
        monotonic = 'yes'
    else:
        monotonic = 'no'
        if xreverse == 'yes':                           # return vectors to thier original state
            x = x[::-1]
            xreverse = 'no'
        if yreverse == 'yes':
            y = y[::-1]
            yreverse = 'no'
        if zreverse == 'yes':
            z = z[::-1]
            zreverse = 'no'

    # note that x, y and z  will be returned reversed as necessary only if monotonic is set to yes

    return x, y, z, monotonic, xreverse, yreverse, zreverse

def printParameterTable():
    """    --------------------------------------------------------------------------------------------------------
     routine:  printParameterTable
     
     purpose:  print the control parameter table using the default values from outside the Shgrid class
     
     usage:    import sh
               sh.printParameterTable()
     
     passed:   nothing 
     
     returned: None
     
     definition: printParameterTable():
--------------------------------------------------------------------------------------------------------""" 

    names = ['name', '----', 'ncl', 'nfl', 'nls']

    parameterDict = {
      'name':('type ','     legal values     ','    default   ', '                     description                        '),
      '----':('-----','----------------------','------------- ', '--------------------------------------------------------'),
      'ncl'  :(' int ','>ncl > 0              ','(n/3)**(1./3.)', 'granularity of 3-D cell grid                           '),
      'nfl'  :(' int ','1<= nfl <= MIN(40,n-1)','32            ', 'number of input data values within radius of influence '),
      'nls'  :(' int ','9<= nls <= MIN(40,n-1)','17            ', 'number of data values used in the least square fit     ')}

    for item in names:
        items = (item, parameterDict[item][0], parameterDict[item][1], parameterDict[item][2], parameterDict[item][3])  
        print '%-6.6s  %-5.6s  %-22.22s   %-14.14s  %s' % items

    return 

def printStoredParameters():
    """    --------------------------------------------------------------------------------------------------------
     routine:  printStoredParameters
     
     purpose: print the values of the current dsgrid control parameters in c code. The call
                   to the method function rgrd will change them to the instance values.
     
     usage:    import sh
               sh.printStoredParameters() 
     
     passed:   nothing 
     
     returned: None
     
     definition: printStoredParameters():
--------------------------------------------------------------------------------------------------------""" 

    names = ['ncl', 'nfl', 'nls']

    typeDict = { 'dmv':'float', 'dmx':'float', 'erf':'char', 'exp':'float', 'shd':'int' }

    for item in names:
        print '   %s = %d' % (item, shgridmodule.shgeti(item))

    return None      

#---------------------------------------------------------------------------------
# ********************************************************************************
# ********************************************************************************
#---------------------------------------------------------------------------------

 

def sendOutput(output, msg, value = None):
    """        #---------------------------------------------------------------------------------
    #
    #    purpose: send the same message to the screen and to a file
    # 
    #    passed :  msg - the string
    #             
    #    returned: return
    #
    #---------------------------------------------------------------------------------"""
    if value is None:
        print msg
        output.write(msg + '\n')
    else:
        print msg, `value`
        output.write(msg + ' %15.11e\n' % (value,))

    return None

def document():
    """        #-------------------------------------------------------------------------
    #
    #    purpose:   'document' writes documentation for the user to a file 
    #
    #    usage:     import sh
    #               sh.document()   
    #    
    #    passed :   nothing
    #
    #    returned:  nothing
    #
    #-------------------------------------------------------------------------"""
    import ds

    std = sys.stdout                                             # save sys.stout to allow reassigning later
    sys.stdout = open( 'shgridmodule.doc', 'w')

    print '**********************************************************************************************\n'  
    print '*************************** Overview of the CDAT interface to shgrid ************************\n'
    print '**********************************************************************************************\n'  
    print sh.__doc__
    print
    print

    print '  ******************** Instructions for use of the shgrid function *****************************'
    print cssgridmodule.shgrid.__doc__
    print

    print '  ******************** Instructions for use of the shgetnp function *****************************'
    print cssgridmodule.shgetnp.__doc__
    print

    print '  ******************** Instructions for use of the shseti function *****************************'
    print cssgridmodule.shseti.__doc__
    print

    print '  ******************** Instructions for use of the shseti function *****************************'
    print cssgridmodule.shgeti.__doc__
    print

    sys.stdout = std

    return None

def help(choice = None):
    import sh

    if choice is None:                               # get instructions for use of help
        print """     ----------------------------------------------------------------------------------------
      
      INSTRUCTIONS ON USE THE OBJECT ORIENTED INTERFACE TO THE SHGRID PACKAGE FROM NGMATH 
     
      This module is built as one class, Shgrid, which sports a single method called rgrd.
     
      To get instructions on making an instance of Shgrid, type
     
              sh.help('Shgrid')
     
      To get instructions on using the control parameters, type
     
              sh.help('parameters')
     
      To print the table describing the control parameters, type
     
              sh.help('table')
     
      To get instructions on performing a regridding, type
     
              sh.help('regrid')
      
      To get instructions finding the nearest point to a point in 3-space, type
     
              sh.help('nearestPoint')
      
     
      INSTRUCTIONS ON USE OF ORIGINAL SHGRID PACKAGE FROM NGMATH 
     
      This module is built as an interface to shgridmodule.so which exports the following functions:
                                                                                                    
                                                                                                    
                        Single precision procedures:                                                    
                                                                                                    
                            shgrid  -- interpolates 3D random data
                            shgetnp -- finds nearest points to a given point in 3-space
                            shseti  -- sets values for the integer control parameters
                            shgeti  -- retrieves values for the integer control parameters
                                                                                                    
                                                                                                    
          It is feasible to use these functions directly without this module. Information is available
          through their docstrings. For example, to get the docstring for the routine shgrid, follow this 
          procedure at the Python prompt:
     
                import shgridmodule
     
                print shgridmodule.shgrid.__doc__
            
                or simply type
     
                sh.help('shgrid')
 
     ------------------------------------------------------------------------------------------------------"""

    elif choice == 'Shgrid': 
        print """     ----------------------------------------------------------------------------------------
                                           
            Array Input And Output Case In Preparation For Interpolation In 3-space

                To make an instance, r, type:
 
                    import sh

                    r = sh.Shgrid(xi, yi, zi, xo, yo, zo) 

                       where xi, yi and zi are the input coordinate arrays in list format
                       while xo, yo and zo are the and output grid coordinate arrays which
                       must be increasing but need not be evenly spaced.
        

            Array Input And Single Point Output Case In Preparation For Finding Nearest Points In 3-space

                To make an instance, r, type:
 
                    import sh

                    r = sh.Shgrid(xi, yi, zi, px, py, pz) 

                       where xi, yi and zi are the input coordinate arrays in list format
                       while px, py and pz are the coordinates of a point whose nearest
                       neighbors are to be found. 

     --------------------------------------------------------------------------------------------------------------------"""
 

    elif choice == 'parameters': 
        print """     ----------------------------------------------------------------------------------------
                                           
             In the absence of an instance of the class Shgrid, a description of the control parameters can be found 
             by typing
     
               import sh
               sh.printParameterTable()
     
     
            After making an instance of Shgrid, r, to look at the default settings for the control parameters and a brief
            description of thier properties, type

                r.printDefaultParameterTable()
 
            To change a setting type the new value. For example, to set ncl to 8, type
 
                r.ncl = 1
 
            To find an individual value,  type the name. For example, to exam the value of nfl, type
 
                r.nfl
     
            To check the settings type
     
                r.printInstanceParameterTable() -- prints the table with values and a description of the parameters
                                                   used in subsequent calls to the method function rgrd
                or

                r.printInstanceParameters()     -- prints a list of the parameters values used in subsequent calls to the 
                                                   the rgrd method

                r. printStoredParameters()    -- prints the parameters in memory which may differ from the above if the
                                                   user has made more than one instance of the Shgrid class.

     --------------------------------------------------------------------------------------------------------------------"""

    elif choice == 'table': 
        printParameterTable()
     
    #-----------------------------------------------------------------------------------------------------

    elif choice == 'regrid':  
        print """     ----------------------------------------------------------------------------------------

            After making the appropriate instance for the interpolation of the Shgrid class, r,  perform an 
            interpolation in 3-space with

                    dataOut = r.rgrd(dataIn) 

                        where dataIn is input data in list form and dataOut is output data in gridded form

     --------------------------------------------------------------------------------------------------------------------"""
    elif choice == 'nearestPoint':  
        print """     ----------------------------------------------------------------------------------------
            After making the appropriate instance for the nearest point computation of the Shgrid class, r,  find the 
            nearest points by typing

                    np = r.rgrd(numberPoints) 

                        where:
                            np is an array with the indices into the input data arrays of the sequence of nearest points.
                            numberPoints is the number of nearest points requested. It may be 1.

               For the ith element in np the point in 3-space is ( xi[np[i]], yi[np[i]], zi[np[i]] ).

     --------------------------------------------------------------------------------------------------------------------"""

    elif choice == 'shgrid':
        print shgridmodule.shgrid.__doc__
    elif choice == 'shseti':
        print shgridmodule.shseti.__doc__
    elif choice == 'shgeti':
        print shgridmodule.shgeti.__doc__
    elif choice == 'shgetnp':
        print shgridmodule.shgetnp.__doc__

    else:
        print 'Your request is not in help.   The help choices are: ' 
        print 'Shgrid, parameters, table, regrid, nearestPoint, shgrid, shseti, shgeti, shgetnp'                               

    return None

